Skip to content

Add role-based HR data agent with scope-based field redaction via AgentCore Gateway#1262

Open
zubeens wants to merge 4 commits intoawslabs:mainfrom
zubeens:feature/role-based-hr-data-agent
Open

Add role-based HR data agent with scope-based field redaction via AgentCore Gateway#1262
zubeens wants to merge 4 commits intoawslabs:mainfrom
zubeens:feature/role-based-hr-data-agent

Conversation

@zubeens
Copy link
Copy Markdown

@zubeens zubeens commented Apr 7, 2026

Summary

  • Adds a new use-case sample demonstrating role-based HR data access with automatic scope-based field redaction using Amazon Bedrock AgentCore
  • Same query, same agent, different OAuth scopes — sensitive fields redacted transparently by the Response Interceptor without changing application code
  • Three personas (HR Manager, HR Specialist, Employee) with different Cognito OAuth scopes controlling both tool visibility and field-level redaction

Key capabilities demonstrated

  • AgentCore Gateway as a policy enforcement point with request/response interceptors
  • Cedar Policy Engine for scope-based tool authorization (tools/call)
  • Response Interceptor for tool discovery filtering (tools/list) and scope-based field redaction
  • Multi-tenant isolation via OAuth client_id → tenant mapping in SSM (no custom JWT claims required)
  • Cognito OAuth 2.0 client_credentials flow with custom scopes per persona

Test plan

  • bash scripts/prereq.sh --region us-east-1 --env dev — deploys Lambda, IAM, Cognito
  • python scripts/agentcore_gateway.py create — creates Gateway with interceptors and Lambda target
  • python scripts/create_cedar_policies.py — attaches Cedar engine and creates 3 HR authorization policies
  • bash scripts/package_runtime.sh && python scripts/agentcore_agent_runtime.py create — deploys Runtime
  • python test/test_dlp_redaction.py — verifies all 4 personas pass field redaction assertions
  • python test/test_agent.py --persona hr-manager --prompt "Show me John Smith's compensation" — full agent test
  • streamlit run app.py — UI smoke test across all personas

Demonstrates scope-based HR data access using AgentCore Gateway interceptors
and Cedar policy engine. An HR Manager sees full employee records; an HR
Specialist sees profiles but not compensation; an Employee sees names only.
DLP redaction is applied transparently by the Response Interceptor — no
application code changes needed when switching personas.
@github-actions github-actions bot added the 02-use-cases 02-use-cases label Apr 7, 2026
@zubeens zubeens changed the title Add role-based HR data agent with field-level DLP via AgentCore Gateway Add role-based HR data agent with scope-based field redaction via AgentCore Gateway Apr 7, 2026
zsahajwani and others added 2 commits April 7, 2026 10:42
- dummy_data.py: MD5 usedforsecurity=False (bandit B324)
- cognito.yaml: RequireSymbols true, AdvancedSecurityMode ENFORCED,
  MFA optional, pragma allowlist secret on GenerateSecret lines (COG1/COG3/detect-secrets)
- infrastructure.yaml: Lambda runtime python3.13, ReservedConcurrentExecutions,
  SQS DLQ with SSE encryption, cdk_nag/checkov suppressions with justifications
  for VPC/DLQ/IAM findings that are sample-appropriate (CKV_AWS_115/116/117,
  AwsSolutions-IAM4/IAM5/L1/SQS3/SQS4/COG2)
- api_spec.json: add securitySchemes + global security field (CKV_OPENAPI_4/5)
- main.py: nosemgrep for BedrockAgentCoreApp.run() false positive
- app.py: nosec B105 for None token initial state false positive
- prereqs_config.yaml: runtime python3.13
- README.md: standard not-for-production disclaimer (matches repo pattern),
  Cognito domain deletion delay note in Cleanup section
- .gitignore: add .ash/ash_output/ to exclude generated scan reports

ASH scan result: 0 actionable findings (bandit, cdk-nag, checkov,
detect-secrets, semgrep all PASSED). 6 suppressions with justifications.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@zubeens
Copy link
Copy Markdown
Author

zubeens commented Apr 13, 2026

Security Scan Results — ASH v3.2.5

All required security fixes have been applied and the ASH scan is clean (exit 0 — 0 actionable findings).

What was fixed

File Finding Fix
prerequisite/lambda/python/dummy_data.py B324 — MD5 used for security usedforsecurity=False
prerequisite/cognito.yaml COG1 — missing symbols in password policy RequireSymbols: true
prerequisite/cognito.yaml COG3 — AdvancedSecurityMode not enforced Added UserPoolAddOns: AdvancedSecurityMode: ENFORCED
prerequisite/cognito.yaml detect-secrets — GenerateSecret: true false positive # pragma: allowlist secret
prerequisite/infrastructure.yaml AwsSolutions-L1 — outdated Lambda runtime Updated all 3 Lambdas to python3.13
prerequisite/infrastructure.yaml CKV_AWS_115 — no concurrency limit Added ReservedConcurrentExecutions to all 3 Lambdas
prerequisite/infrastructure.yaml CKV_AWS_116 — no DLQ on main Lambda Added SQS DLQ with SSE encryption + IAM grant
prerequisite/lambda/api_spec.json CKV_OPENAPI_4/5 — no security field Added securitySchemes (OAuth2) + global security array
main.py semgrep false positive on app.run() # nosemgrep — this is BedrockAgentCoreApp, not Flask
app.py B105 false positive on None token # nosec B105 with explanation
README.md Missing standard disclaimer Added repo-standard not-for-production notice
.gitignore .ash/ash_output/ not excluded Added to .gitignore

Suppressions with justification (6 total)

All suppressions include documented justifications in the CloudFormation Metadata blocks:

  • CKV_AWS_117 (Lambda VPC) — sample code; VPC adds significant deployment complexity outside the scope of this AgentCore Gateway demonstration
  • CKV_AWS_116 (DLQ on interceptors) — interceptors are invoked synchronously by AgentCore Gateway; DLQ applies only to async/event-source invocations
  • AwsSolutions-SQS3 (DLQ needs a DLQ) — this queue IS the DLQ; circular by definition
  • AwsSolutions-SQS4 (SQS SSL) — encrypted at rest via SSE-SQS (SqsManagedSseEnabled: true)
  • AwsSolutions-IAM4/IAM5AWSLambdaBasicExecutionRole is standard practice; bedrock-agentcore:* has no resource-level ARN support; SSM path scoped to /app/hrdlp/*
  • AwsSolutions-COG2 (MFA) — sample/demo environment; MFA optional to reduce setup friction

ASH Security Scan Report

  • Report generated: 2026-04-13T18:42:32+00:00
  • Time since scan: 0 minutes

Scan Metadata

  • Project: ASH
  • Scan executed: 2026-04-13T18:41:35+00:00
  • ASH version: 3.2.5

Summary

Scanner Results

The table below shows findings by scanner, with status based on severity thresholds and dependencies:

  • Severity levels:
    • Suppressed (S): Findings that have been explicitly suppressed and don't affect scanner status
    • Critical (C): Highest severity findings that require immediate attention
    • High (H): Serious findings that should be addressed soon
    • Medium (M): Moderate risk findings
    • Low (L): Lower risk findings
    • Info (I): Informational findings with minimal risk
  • Duration (Time): Time taken by the scanner to complete its execution
  • Actionable: Number of findings at or above the threshold severity level that require attention
  • Result:
    • PASSED = No findings at or above threshold
    • FAILED = Findings at or above threshold
    • MISSING = Required dependencies not available
    • SKIPPED = Scanner explicitly disabled
    • ERROR = Scanner execution error
  • Threshold: The minimum severity level that will cause a scanner to fail
    • Thresholds: ALL, LOW, MEDIUM, HIGH, CRITICAL
    • Source: Values in parentheses indicate where the threshold is set:
      • global (global_settings section in the ASH_CONFIG used)
      • config (scanner config section in the ASH_CONFIG used)
      • scanner (default configuration in the plugin, if explicitly set)
  • Statistics calculation:
    • All statistics are calculated from the final aggregated SARIF report
    • Suppressed findings are counted separately and do not contribute to actionable findings
    • Scanner status is determined by comparing actionable findings to the threshold
Scanner Suppressed Critical High Medium Low Info Actionable Result Threshold
bandit 0 0 0 0 32 0 0 PASSED MEDIUM (global)
cdk-nag 0 0 0 0 0 19 0 PASSED MEDIUM (global)
cfn-nag 0 0 0 0 0 0 0 MISSING MEDIUM (global)
checkov 6 0 0 0 0 0 0 PASSED MEDIUM (global)
detect-secrets 0 0 0 0 0 0 0 PASSED MEDIUM (global)
grype 0 0 0 0 0 0 0 MISSING MEDIUM (global)
npm-audit 0 0 0 0 0 0 0 PASSED MEDIUM (global)
opengrep 0 0 0 0 0 0 0 MISSING MEDIUM (global)
semgrep 1 0 0 0 0 0 0 PASSED MEDIUM (global)
syft 0 0 0 0 0 0 0 MISSING MEDIUM (global)

Report generated by Automated Security Helper (ASH) at 2026-04-13T18:42:32+00:00

@zubeens
Copy link
Copy Markdown
Author

zubeens commented Apr 14, 2026

AWS Holmes Security Scan — Findings Fixed

Ran AWS Holmes (HolmesContentSecurityReviewBaselinePolicy) against the full sample. The scan reported 108 findings across 27 files. All actionable findings have been fixed or suppressed with justification in this PR update.


Real Fixes Applied

Finding File Change
Hardcoded AWS account ID 943677087104 in Gateway ARNs prerequisite/cedar/hr_dlp_policies.cedar Replaced with <YOUR-ACCOUNT-ID>/<YOUR-GATEWAY-ID> placeholders; added instructions to substitute before deployment
S3 bucket created without Block Public Access scripts/prereq.sh Added put-public-access-block (BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, RestrictPublicBuckets all true)
S3 bucket created without encryption at rest scripts/prereq.sh Added put-bucket-encryption with SSE-S3 (AES-256)
S3 bucket created without TLS enforcement scripts/prereq.sh Added put-bucket-policy denying all non-TLS (aws:SecureTransport: false) requests
cfn-guard SQS_QUEUE_KMS_MASTER_KEY_ID_RULE on DLQ prerequisite/infrastructure.yaml Added guard.SuppressedRules — queue uses SqsManagedSseEnabled: true; rule only checks KmsMasterKeyId
cfn-guard IAM_NO_INLINE_POLICY_CHECK (×3) prerequisite/infrastructure.yaml Added guard.SuppressedRules on HRLambdaExecutionRole, AgentCoreGatewayRole, AgentCoreRuntimeRole — inline policies scoped exclusively to each role; sample code pattern
cfn-guard LAMBDA_INSIDE_VPC (×3) prerequisite/infrastructure.yaml Added guard.SuppressedRules — already suppressed via checkov.skip CKV_AWS_117; cfn-guard required a separate entry
cfn-guard LAMBDA_DLQ_CHECK (×2) prerequisite/infrastructure.yaml Added guard.SuppressedRules on interceptor Lambdas — already suppressed via checkov.skip CKV_AWS_116; interceptors are invoked synchronously by AgentCore Gateway, DLQs apply only to async invocations
Stale AwsSolutions-L1 reason text referencing python3.12 prerequisite/infrastructure.yaml Updated to python3.13 to match actual runtime
SSM informal name in docstring and log message agent_config/utils.py Docstring updated to "AWS Systems Manager Parameter Store"; log switches to %s format and logs error code only (not full exception)
AWS Service Name Standards — "AgentCore" without "Amazon Bedrock" prefix on first mention 15 files Updated first-mention in module docstrings across agent_config/, app_modules/, scripts/, prerequisite/lambda/, test/, docs/diagrams/, main.py, app.py
AWS Service Name Standards — section headers in CloudFormation prerequisite/infrastructure.yaml Updated comments: Lambda → AWS Lambda, SQS → Amazon SQS, IAM → AWS Identity and Access Management (IAM)
AWS Service Name Standards — "Cognito" without "Amazon" prefix prerequisite/cedar/hr_dlp_policies.cedar Updated to "Amazon Cognito"
Superlative language ("will pass", "Always run", "never reach") README.md Softened to "expected to pass", "Run the full update command", "sensitive fields are withheld"

Justified Suppressions (Not Fixed)

Finding File(s) Reason
URL Validationhttp://localhost:8501 cognito.yaml, README.md, app_modules/auth.py, app.py Cognito OAuth callback URL for local Streamlit dev; localhost must use HTTP — HTTPS is not valid here
URL Validation — template patterns ({region}, {user_pool_id}) scripts/agentcore_agent_runtime.py, scripts/agentcore_gateway.py, prerequisite/lambda/api_spec.json URL-shaped string templates with placeholders, not actual URLs — scanner fails to validate them
IAM_NO_INLINE_POLICY_CHECK (cfn-guard) prerequisite/infrastructure.yaml Suppressed via guard.SuppressedRules — policies are role-scoped; standalone managed policies add complexity with no security benefit in a demo sample
LAMBDA_INSIDE_VPC (cfn-guard) prerequisite/infrastructure.yaml Suppressed — VPC configuration requires subnets, security groups, and VPC endpoints that are outside the scope of this AgentCore Gateway demonstration
LAMBDA_DLQ_CHECK on interceptors (cfn-guard) prerequisite/infrastructure.yaml Suppressed — interceptors are synchronously invoked by AgentCore Gateway; DLQs apply to async/event-source invocations only
CKV_AWS_27 (Checkov) prerequisite/infrastructure.yaml Already suppressed via checkov.skip + SqsManagedSseEnabled: true; rule checks KmsMasterKeyId only; SSE-SQS provides equivalent encryption
GenAI, AI Security and Dataset Compliance — missing Bedrock Guardrails agent_config/agent.py, main.py Guardrail integration is a production hardening step outside the scope of this demo sample
Legal Compliance — per-file license headers Cedar, Python scripts, policy text files Repo-level MIT LICENSE file at root covers all files per OSI standard practice
IAM wildcard for X-Ray / AgentCore actions prerequisite/infrastructure.yaml X-Ray (xray:*) and bedrock-agentcore:GetWorkloadAccessTokenForUserId / CreateWorkloadIdentity do not support resource-level ARN restrictions
CloudWatch Logs encryption prerequisite/infrastructure.yaml KMS-encrypted log groups add deployment prerequisites (key creation, IAM grants) outside demo scope

…-guard suppressions, naming standards

AWS Holmes (HolmesContentSecurityReviewBaselinePolicy) reported 108 findings.
All actionable findings addressed:

Security fixes:
- Cedar: replace hardcoded AWS account ID 943677087104 with <YOUR-ACCOUNT-ID> placeholder
- S3: add Block Public Access, AES-256 encryption, and TLS-only bucket policy in prereq.sh

CloudFormation cfn-guard suppressions (guard.SuppressedRules):
- SQS_QUEUE_KMS_MASTER_KEY_ID_RULE on DLQ (uses SqsManagedSseEnabled)
- IAM_NO_INLINE_POLICY_CHECK on all 3 IAM roles
- LAMBDA_INSIDE_VPC on all 3 Lambda functions
- LAMBDA_DLQ_CHECK on interceptor Lambdas (synchronous invocation)

Documentation / naming:
- AWS Service Name Standards: "Amazon Bedrock AgentCore" first-mention across 15 files
- CloudFormation section comments: AWS Lambda, Amazon SQS, AWS IAM full names
- README: soften superlative language; update AwsSolutions-L1 reason to python3.13
- utils.py: docstring uses "AWS Systems Manager Parameter Store"; safer log format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

02-use-cases 02-use-cases

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants